package com.greensock.core 
{
	import com.greensock.*;


public class TweenCore
{
	
	public function TweenCore(duration:Number = 0, vars:Object = null) 
	{
		// 参数
		this.vars             =  (vars != null) ? vars : { };
		
		// 持续时间
		this.cachedDuration   =  this.cachedTotalDuration = duration;
		
		// 延迟时间
		_delay                =  (this.vars.delay) ? Number(this.vars.delay) : 0;
		
		// 时间比例
		this.cachedTimeScale  =  (this.vars.timeScale) ? Number(this.vars.timeScale) : 1
		
		
		this.active           =  Boolean(duration == 0 && _delay == 0 && this.vars.immediateRender != false);
		
		
		this.cachedTotalTime  =  this.cachedTime = 0;
		
		// 总初期化
		if (!_classInitted) 
		{
			if (isNaN(TweenLite.rootFrame))
			{
				TweenLite.initClass();
				_classInitted = true;
			}
			
			else 
			{
				return;
			}
		}
		
		// 加至时间线
		var tl:SimpleTimeline = (this.vars.timeline is SimpleTimeline) ? this.vars.timeline : (this.vars.useFrames) ? TweenLite.rootFramesTimeline : TweenLite.rootTimeline;
		tl.insert(this, tl.cachedTotalTime);
		
		// 反转
		if (this.vars.reversed)  this.cachedReversed = true;
		
		// 暂停
		if (this.vars.paused)    this.paused = true;
	}
	

	
	protected static var _classInitted:Boolean;
	
	protected var _delay:Number; 
	
	protected var _hasUpdate:Boolean;
	
	protected var _rawPrevTime:Number = -1;
	
	public var vars:Object; 
	
	public var active:Boolean; 
	
	public var gc:Boolean
	
	public var initted:Boolean; 
	
	public var timeline:SimpleTimeline;
	
	public var cachedStartTime:Number; 
	/** @private The last rendered currentTime of this TweenCore. If a tween is going to repeat, its cachedTime will reset even though the cachedTotalTime continues linearly (or if it yoyos, the cachedTime may go forwards and backwards several times over the course of the tween). The cachedTime reflects the tween's "local" (which can never exceed the duration) time whereas the cachedTotalTime reflects the overall time. These will always match if the tween doesn't repeat/yoyo.**/
	public var cachedTime:Number; 
	/** @private The last rendered totalTime of this TweenCore. It is prefaced with "cached" because using a public property like this is faster than using the getter which is essentially a function call. If you want to update the value, you should always use the normal property, like myTween.totalTime = 0.5.**/
	public var cachedTotalTime:Number; 
	
	public var cachedDuration:Number; 
	
	public var cachedTotalDuration:Number; 
	
	public var cachedTimeScale:Number;    // 时间比例
	
	public var cachedPauseTime:Number;
	
	public var cachedReversed:Boolean;
	
	public var nextNode:TweenCore, prevNode:TweenCore;
	
	public var cachedOrphan:Boolean;
	
	public var cacheIsDirty:Boolean; 
	
	public var cachedPaused:Boolean; 
	

	public function renderTime(time:Number, suppressEvents:Boolean=false, force:Boolean=false):void
    {	
	}
    
    public function invalidate():void 
    {	
    }
    
	
	public function complete(skipRender:Boolean = false, suppressEvents:Boolean = false):void
	{
		if (!skipRender) 
		{
			renderTime(this.totalDuration, suppressEvents, false); //just to force the final render
			return; //renderTime() will call complete() again, so just return here.
		}
		
		if (this.timeline.autoRemoveChildren)
		{
			this.setEnabled(false, false);
		} 
		
		else
		{
			this.active = false;
		}
		
		if (!suppressEvents) 
		{
			if (this.vars.onComplete && this.cachedTotalTime >= this.cachedTotalDuration && !this.cachedReversed) 
			{ //note: remember that tweens can have a duration of zero in which case their cachedTime and cachedDuration would always match. Also, TimelineLite/Max instances with autoRemoveChildren may have a cachedTotalTime that exceeds cachedTotalDuration because the children were removed after the last render.
				this.vars.onComplete.apply(null, this.vars.onCompleteParams);
			} 
			
			else if (this.cachedReversed && this.cachedTotalTime == 0 && this.vars.onReverseComplete)
			{
				this.vars.onReverseComplete.apply(null, this.vars.onReverseCompleteParams);
			}
		}
	}


	public function setEnabled(enabled:Boolean, ignoreTimeline:Boolean = false):Boolean
	{
		this.gc = !enabled
		
		if (enabled) 
		{
			this.active = Boolean(!this.cachedPaused && this.cachedTotalTime > 0 && this.cachedTotalTime < this.cachedTotalDuration);
			if (!ignoreTimeline && this.cachedOrphan)
			{
				this.timeline.insert(this, this.cachedStartTime - _delay);
			}
		} 
		
		else
		{
			this.active = false;
			if (!ignoreTimeline && !this.cachedOrphan) 
			{
				this.timeline.remove(this, true);
			}
		}
		return false;
	}

	
	protected function setDirtyCache(includeSelf:Boolean = true):void 
	{
		var tween:TweenCore = (includeSelf) ? this : this.timeline;
		while (tween) 
		{
			tween.cacheIsDirty = true;
			tween = tween.timeline;
		}
	}
	
	
	protected function setTotalTime(time:Number, suppressEvents:Boolean = false):void 
	{
		if (this.timeline) 
		{
			var tlTime:Number = (this.cachedPaused) ? this.cachedPauseTime : this.timeline.cachedTotalTime;
			if (this.cachedReversed)
			{
				var dur:Number = (this.cacheIsDirty) ? this.totalDuration : this.cachedTotalDuration;
				this.cachedStartTime = tlTime - ((dur - time) / this.cachedTimeScale);
			} 
			
			else
			{
				this.cachedStartTime = tlTime - (time / this.cachedTimeScale);
			}
			
			if (!this.timeline.cacheIsDirty)
			{ //for performance improvement. If the parent's cache is already dirty, it already took care of marking the anscestors as dirty too, so skip the function call here.
				setDirtyCache(false);
			}
			
			if (this.cachedTotalTime != time)
			{
				renderTime(time, suppressEvents, false);
			}
		}
	}
	
	
	public function get currentTime():Number {return this.cachedTime;}
	public function set currentTime(n:Number):void 
	{
		setTotalTime(n, false);
	}
	

	public function get delay():Number { return _delay; }
	public function set delay(n:Number):void 
	{
		this.startTime += n - _delay;
		_delay = n;
	}
	
	
	public function get duration():Number { return this.cachedDuration; }
	public function set duration(n:Number):void {
		var ratio:Number = n / this.cachedDuration;
		this.cachedDuration = this.cachedTotalDuration = n;
		if (this.active && !this.cachedPaused && n != 0) {
			this.setTotalTime(this.cachedTotalTime * ratio, true);
		}
		setDirtyCache(false);
	}
	

	public function get totalDuration():Number { return this.cachedTotalDuration; }
	public function set totalDuration(n:Number):void {this.duration = n;}


	public function get startTime():Number { return this.cachedStartTime; }
	public function set startTime(n:Number):void {
		if (this.timeline != null && (n != this.cachedStartTime || this.gc)) 
		{
			this.timeline.insert(this, n - _delay); //ensures that any necessary re-sequencing of TweenCores in the timeline occurs to make sure the rendering order is correct.
		} else {
			this.cachedStartTime = n;
		}
	}
	

	public function get reversed():Boolean { return this.cachedReversed; }
	public function set reversed(b:Boolean):void
	{
		if (b != this.cachedReversed) 
		{
			this.cachedReversed = b;
			setTotalTime(this.cachedTotalTime, true);
		}
	}
	
	public function get paused():Boolean { return this.cachedPaused; }
	public function set paused(b:Boolean):void
    {
		if (b != this.cachedPaused && this.timeline)
		{
			if (b) 
			{
				this.cachedPauseTime = this.timeline.rawTime;
			} 
			
			else 
			{
				this.cachedStartTime += this.timeline.rawTime - this.cachedPauseTime;
				this.cachedPauseTime = NaN;
				setDirtyCache(false);
			}
			
			this.cachedPaused = b;
			this.active = Boolean(!this.cachedPaused && this.cachedTotalTime > 0 && this.cachedTotalTime < this.cachedTotalDuration);
		}
		
		if (!b && this.gc)
		{
			this.setEnabled(true, false);
		}
	}

}
}